home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Snippets / Networking / ADSP Chat / ADSP.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  31.9 KB  |  1,222 lines  |  [TEXT/MPS ]

  1. /*****************************************************************
  2.  
  3.     Program:    < ADSP Chat >
  4.     File:        < adsp.c >
  5.     
  6.     Written by  Pete Helm, Scott Kuechle
  7.     of <Apple Macintosh Developer Technical Support>
  8.     
  9.     modified by Scott Kuechle
  10.     10/92 SRK Converted from Pascal to C
  11.     8/94 SRK Modified to use a queue of parameter
  12.              blocks.
  13.  
  14.     Copyright © 1992, 1994 Apple Computer, Inc.
  15.     All rights reserved.
  16.     
  17. *****************************************************************/
  18.  
  19. /*****************************************************************/
  20. /*  I N C L U D E S
  21. /*****************************************************************/
  22.  
  23. #include    "ADSP Chat.h"
  24.  
  25. /********************************************************************
  26. /*  G L O B A L   V A R I A B L E   D E C L A R A T I O N S
  27. /********************************************************************/
  28.  
  29. char myLocalSocket;
  30. Ptr receiveQBuffer;
  31. Ptr sendQBuffer;
  32. Ptr attnBuffer;
  33. Ptr outAttnBuff;
  34. Ptr receiveBuffer;
  35. Ptr outgoingDataBuffer;
  36.  
  37.  
  38. TRCCB    gMyCCB;                /* our ccb */
  39. short     gADSPDrvrRefNum;    /* adsp driver reference number */
  40. short     gCCBRefNum;            /* ccb reference number returned by adsp on a dspInit */
  41.  
  42. Boolean gJustConnected;        /* dspOpen ocRequest was successfully accepted */
  43.  
  44. QHdr    gAvailQueue;
  45. QHdr    gDoneQueue;
  46. QHdr    gReadQueue;
  47.  
  48. /*****************************************************************/
  49. /*
  50. /* E X T E R N A L S
  51. /*
  52. /*****************************************************************/
  53.  
  54. extern void removeMyName();
  55.  
  56. extern Boolean    registerMyName();
  57. extern void ShowError(short index);
  58. extern void DisplayCurrentStatus(Ptr displayStr);
  59. extern void HiliteConnectButton (short mode);
  60. extern void Exit(short message);
  61.  
  62. extern Str255 gZoneString, gObjStr, gTypeStr;
  63. extern Str32 myName;
  64. extern DialogPtr myDialog;
  65. extern QHdr freeQHdr,saveErrorQHdr;
  66. extern AddrBlock ourNetworkAddress;
  67. extern void CopyPstr(Ptr pSource, Ptr pDest);
  68. extern void PStrCat(Ptr sourceStr, Ptr destinationStr);
  69. extern void zeroOutStrings();
  70. extern void PreCompletion();
  71.  
  72.  
  73.  
  74.  
  75. #pragma segment adsp
  76. // *****************************************************************
  77. // *    doADSPinit
  78. // *
  79. // *    calls dspInit, saves the socket and ccb refnum returned
  80. // *****************************************************************
  81. Boolean doADSPinit(unsigned char *localSocket,
  82.                     short *ccbRefNum,
  83.                     TPCCB ccbPtr)
  84. {
  85. TRinitParams *initParmsPtr;
  86. DSPParamBlock dspPB;
  87.  
  88.         /* allocate connection end */
  89.     dspPB.ioCRefNum     = gADSPDrvrRefNum;
  90.     dspPB.csCode         = dspInit;
  91.     
  92.     initParmsPtr = &dspPB.u.initParams;
  93.     
  94.     initParmsPtr->ccbPtr         = ccbPtr;
  95.         /* poll in main event loop instead of using user routine */
  96.     initParmsPtr->userRoutine    = NULL;
  97.     initParmsPtr->sendQSize     = Qsize;
  98.     initParmsPtr->sendQueue     = sendQBuffer;
  99.     initParmsPtr->recvQSize     = Qsize;
  100.     initParmsPtr->recvQueue     = receiveQBuffer;
  101.     initParmsPtr->attnPtr         = attnBuffer;
  102.     initParmsPtr->localSocket     = 0;                 /* dynamically allocate a socket for us */
  103.  
  104.     if (PBControl((ParmBlkPtr)&dspPB, false) != noErr)
  105.         Exit(DrvrErr);
  106.     else if ( dspPB.ioResult == noErr)    /* any errors? */
  107.     {
  108.             /* save socket returned to us by ADSP */
  109.         *localSocket = initParmsPtr->localSocket;
  110.  
  111.             /* save ccb reference number returned to us by ADSP */
  112.         *ccbRefNum = dspPB.ccbRefNum;
  113.         return true;
  114.     }
  115.     else    /* got an error on the dspInit */
  116.     {
  117.         *ccbRefNum = 0;
  118.         ShowError(dspInitErr);
  119.         return false;
  120.     }
  121. }
  122.  
  123. // *****************************************************************
  124. // *    initializeADSP
  125. // *
  126. // *    opens the adsp driver, allocates memory for our adsp buffers
  127. // *    then issues a passive open call
  128. // *****************************************************************
  129. void initializeADSP()
  130. {
  131.         /* set up the ADSP connection end. */
  132.     gJustConnected = false;
  133.     gCCBRefNum = 0;
  134.  
  135.     changeConnectButtonState();
  136.     
  137.         /* open the ADSP driver here - we need the reference number
  138.             for all ADSP calls */
  139.     if (OpenDriver("\p.DSP", &gADSPDrvrRefNum) != noErr)
  140.         Exit(atalkErr);
  141.         
  142.     if (InitQueues() == noErr)
  143.     {
  144.             /* allocate memory for our buffers and then
  145.                 issue a passive open */
  146.         if (setUpADSPbuffers() == true)
  147.         {
  148.                 /* issue a passive open */
  149.             if (WaitForConnectionRequest() != true)
  150.             {
  151.                     /* oops! got an error so deallocate our buffers */
  152.                 removeADSPBuffers();
  153.                 Exit(memErr);
  154.             }
  155.         }
  156.         else
  157.             Exit(noMemErr);
  158.     }
  159.     else
  160.         Exit(memErr);
  161.  
  162. }
  163.  
  164.  
  165. // *****************************************************************
  166. // *    SetOurCompletionRoutine
  167. // *
  168. // *    Sets the "real" completion routine for our async. calls
  169. // *****************************************************************
  170.  
  171. void SetOurCompletionRoutine(ProcPtr procPtr,
  172.                             DSPPBPtr dspPBPtr)
  173. {
  174. Ptr p;
  175. myDSPParamBlockPtr myDSPPBPtr;
  176.  
  177.     p = (Ptr)dspPBPtr;
  178.         /* the "ourCompletion" field is offset
  179.             8 bytes above the DSPParmBlock in
  180.             our definition */
  181.     myDSPPBPtr = (myDSPParamBlockPtr)(p - 8);
  182.     myDSPPBPtr->ourCompletion = procPtr;
  183.     
  184. }
  185.  
  186. // *****************************************************************
  187. // *    GetQElement
  188. // *
  189. // *    retrieve a queue element from the specified queue
  190. // *****************************************************************
  191.  
  192. DSPPBPtr GetQElement(QHdrPtr qHdrPtr)
  193. {
  194. OSErr err;
  195. QElemPtr qElemPtr;
  196.  
  197.     CheckDoneQueue();
  198.  
  199.     qElemPtr = qHdrPtr->qHead;
  200.     if (qElemPtr != NULL)
  201.     {
  202.         err = Dequeue((QElemPtr)qElemPtr,qHdrPtr);
  203.         if (err != noErr)
  204.         {
  205.             return NULL;
  206.         }
  207.         else
  208.         {
  209.             return (DSPPBPtr)(qElemPtr);
  210.         }
  211.     }
  212.     else
  213.         return NULL;
  214. }
  215.  
  216. // *****************************************************************
  217. // *    InitQueues
  218. // *
  219. // *    initialize our "Available" , "Done" and "Read" queues
  220. // *****************************************************************
  221.  
  222. OSErr InitQueues()
  223. {
  224. short i;
  225. OSErr err;
  226. long myA5;
  227. myDSPParamBlockPtr myQElem;
  228.  
  229.  
  230.     gAvailQueue.qHead = NULL;
  231.     gAvailQueue.qTail = NULL;
  232.  
  233.     gDoneQueue.qHead = NULL;
  234.     gDoneQueue.qTail = NULL;
  235.  
  236.     gReadQueue.qHead = NULL;
  237.     gReadQueue.qTail = NULL;
  238.     
  239.     err = noErr;
  240.     myA5 = *(long *)CurrentA5;
  241.     
  242.     for (i=0; (i < maxQElements) || (err != noErr); ++i)
  243.     {
  244.         myQElem = (myDSPParamBlockPtr)NewPtr(sizeof(myDSPParamBlock));
  245.         if (myQElem != NULL)
  246.         {
  247.             myQElem->myA5 = myA5;
  248.             myQElem->u.ioCompletion = (ProcPtr)&PreCompletion;
  249.             Enqueue((QElemPtr)&myQElem->u,&gAvailQueue);
  250.         }
  251.         else
  252.         {
  253.             err = MemError();
  254.         }
  255.     }
  256.  
  257.     return err;
  258. }
  259.  
  260. // *****************************************************************
  261. // *    setUpADSPbuffers
  262. // *
  263. // *    allocates memory for our adsp buffers
  264. // *****************************************************************
  265. Boolean setUpADSPbuffers()
  266. {
  267.     
  268.     receiveQBuffer = NewPtr(Qsize);
  269.     if ( receiveQBuffer == nil) return false;
  270.  
  271.     sendQBuffer = NewPtr(Qsize);    
  272.     if ( sendQBuffer == nil) return false;
  273.     
  274.     attnBuffer = NewPtr(attnBufSize);
  275.     if ( attnBuffer == nil) return false;
  276.     
  277.     outAttnBuff = NewPtr(attnBufSize);
  278.     if ( outAttnBuff == nil) return false;
  279.     
  280.     receiveBuffer = NewPtr(attnBufSize);
  281.     if ( receiveBuffer == nil) return false;
  282.     
  283.     outgoingDataBuffer = NewPtr(Qsize);
  284.     if ( outgoingDataBuffer == nil) return false;
  285.     
  286.     return true;
  287.     
  288. }
  289.  
  290.  
  291.  
  292. // *****************************************************************
  293. // *    changeConnectButtonState
  294. // *
  295. // *    sets the correct state for our connect button
  296. // *****************************************************************
  297. void changeConnectButtonState()
  298. {
  299.     /* this procedure reflects the state of our connection in the control */
  300.  
  301.     Rect r;
  302.     short kind;
  303.     Handle h;
  304.  
  305.         GetDItem(myDialog, kConnectButtonID, &kind, &h, &r);
  306.         
  307.         if ( (gCCBRefNum == 0) ||
  308.             ((gCCBRefNum != 0) && (gMyCCB.state == sClosed)) )
  309.             SetCTitle((ControlHandle)h, "\pConnect");
  310.         else
  311.         {
  312.             SetCTitle((ControlHandle)h, "\pDisconnect");
  313.             HiliteConnectButton(0);
  314.         }
  315. }
  316.  
  317. // *****************************************************************
  318. // *    DisplayTime
  319. // *
  320. // *    this procedure responds to an attention message from the remote
  321. // *    Mac which contains the time of that Mac.  Silly yes, but it does
  322. // *    show how to use the attnMsg stuff.
  323. // *****************************************************************
  324. void DisplayTime()
  325. {
  326.  
  327.     Rect r;
  328.     short kind;
  329.     Handle h;
  330.     long dateTime;
  331.     Str255 str, str2;
  332.  
  333.         GetDItem(myDialog, kRemoteMacsTimeID, &kind, &h, &r);
  334.         GetIText(h, str2);
  335.         BlockMove(attnBuffer, &dateTime, 4);
  336.         IUTimeString(dateTime, true, str);
  337.  
  338.         /* this just checks to see that we're not already displaying this time already */
  339.         /* flashing text sucks... so sayeth me */
  340.         if (IUCompString(str,str2) != 0)
  341.             SetIText(h, str);
  342. }
  343.  
  344. // *****************************************************************
  345. // *    DisplayTheirName
  346. // *
  347. // *    this procedure responds to an attention message from the remote
  348. // *    Mac which contains the remote Mac's Chooser name.
  349. // *****************************************************************
  350. void DisplayTheirName()
  351. {
  352.     
  353.     Rect r;
  354.     short kind;
  355.     Handle h;
  356.     Str255 str;
  357.     
  358.         GetDItem(myDialog, kRemoteMacsNameID, &kind, &h, &r);
  359.         BlockMove(attnBuffer, &str, 255);
  360.         SetIText(h, str);
  361. }
  362.  
  363. // *****************************************************************
  364. // *    DisplayIncomingText
  365. // *
  366. // *    this procedure takes the text written to our receive buffer from
  367. // *    the remote Mac and displays the text in a dialog item
  368. // *****************************************************************
  369. void DisplayIncomingText(DSPPBPtr dspPBPtr)
  370. {
  371.  
  372.     Rect r;
  373.     short kind;
  374.     Handle h;
  375.     Str255 str;
  376.  
  377.         GetDItem(myDialog, kIncomingTextID, &kind, &h, &r);
  378.         BlockMove(dspPBPtr->u.ioParams.dataPtr, (Ptr)(&str[1]), 255);
  379.  
  380.         str[0] = (char)dspPBPtr->u.ioParams.actCount;
  381.         SetIText(h, &str);
  382.  
  383. }
  384.  
  385.  
  386. // *****************************************************************
  387. // *    removeADSPBuffers
  388. // *
  389. // *    this procedure deallocates the memory for our adsp buffers.
  390. // *****************************************************************
  391. void removeADSPBuffers()
  392. {
  393.     if (receiveQBuffer != NULL)
  394.         DisposPtr(receiveQBuffer);
  395.     if (sendQBuffer != NULL)
  396.         DisposPtr(sendQBuffer);
  397.     if (attnBuffer != NULL)
  398.         DisposPtr(attnBuffer);
  399.     if (outAttnBuff != NULL)
  400.         DisposPtr(outAttnBuff);
  401.     if (receiveBuffer != NULL)
  402.         DisposPtr(receiveBuffer);
  403.     if (outgoingDataBuffer != NULL)
  404.         DisposPtr(outgoingDataBuffer);
  405.  
  406. }
  407.  
  408. // *****************************************************************
  409. // *    CloseTheConnection
  410. // *
  411. // *    calls dspClose to close the connection end.
  412. // *****************************************************************
  413. void CloseTheConnection(short ccbRefNum)
  414. {
  415.     DSPParamBlock pb;
  416.  
  417.         pb.ioCRefNum             = gADSPDrvrRefNum;
  418.         pb.csCode                 = dspClose;
  419.         pb.ccbRefNum             = ccbRefNum;
  420.         pb.u.closeParams.abort     = 1;        /* non zero value aborts any outstanding calls */
  421.  
  422.         if (PBControl((ParmBlkPtr)&pb, false) != noErr)
  423.             Exit(DrvrErr);
  424. }
  425.  
  426.  
  427. // *****************************************************************
  428. // *    removeConnectionEnd
  429. // *
  430. // *    calls dspRemove to eliminate the connection end.
  431. // *****************************************************************
  432. void removeConnectionEnd(short ccbRefNum)
  433. {
  434.     DSPParamBlock pb;
  435.  
  436.         pb.ioCRefNum             = gADSPDrvrRefNum;
  437.         pb.csCode                 = dspRemove;
  438.         pb.ccbRefNum             = ccbRefNum;
  439.         pb.u.closeParams.abort     = 1;        /* non zero value aborts any outstanding calls */
  440.  
  441.         if (PBControl((ParmBlkPtr)&pb, false) != noErr)
  442.             Exit(DrvrErr);
  443.  
  444.         if (pb.ioResult != noErr)
  445.             ShowError(dspRemoveErr);
  446. }
  447.  
  448. // *****************************************************************
  449. // *    WaitForConnectionRequest
  450. // *
  451. // *    calls dspInit to establish a connection end. Then registers
  452. // *    our name on the net and does a passive open.
  453. // *****************************************************************
  454. Boolean WaitForConnectionRequest()
  455. {
  456. DSPPBPtr dspPBPtr;
  457.  
  458.         /* first issue a dspInit */
  459.     if (doADSPinit(&myLocalSocket,
  460.                     &gCCBRefNum,
  461.                     &gMyCCB) == true)
  462.     {
  463.             /* save our socket for comparison purposes later */
  464.         ourNetworkAddress.aSocket = myLocalSocket;
  465.  
  466.             /* now register our nbp name with type "moof" */
  467.         if (registerMyName() == true)
  468.         {
  469.                 /* get QElement for the dspInit call */
  470.             dspPBPtr = GetQElement(&gAvailQueue);
  471.             if (dspPBPtr != NULL)
  472.             {
  473.                     /* do a passive open, waiting for open requests */
  474.                 DoPassiveOpen(dspPBPtr,
  475.                                 gCCBRefNum);
  476.                 return true;
  477.             }
  478.         }
  479.         else    /* we got an error! */
  480.         {        /* remove connection end with dspRemove */
  481.             removeConnectionEnd(gCCBRefNum);
  482.                 /* de-allocate memory we got for our buffers */
  483.             removeADSPBuffers();
  484.         }
  485.     }
  486.  
  487.     return false;
  488. }
  489.  
  490. // *****************************************************************
  491. // *    CloseConnection
  492. // *
  493. // *    calls dspRemove to eliminate the connection end. Then removes
  494. // *    our nbp name from the net and re-issues a passive open.
  495. // *****************************************************************
  496. void CloseConnection()
  497. {
  498.         /* do a dspRemove to close the connection end */
  499.     removeConnectionEnd(gCCBRefNum);
  500.     
  501.         /* remove our nbp name "moof" */
  502.     removeMyName();
  503.  
  504.     changeConnectButtonState();
  505.     zeroOutStrings();
  506.  
  507.         /* at this point, we have closed the connection so let's issue
  508.             an asynchronous passive open. This call will complete whenever
  509.             we receive an open connection request from another machine. */
  510.     WaitForConnectionRequest();
  511.  
  512. }
  513.  
  514.  
  515. // *****************************************************************
  516. // *    sendAttnMsgCompRoutine
  517. // *
  518. // *    when our send attention message call completes this procedure
  519. // *    will get called.
  520. // *****************************************************************
  521. pascal void sendAttnMsgCompRoutine(DSPPBPtr dspPBPtr)
  522. {
  523.     if (dspPBPtr->ioResult == noErr)
  524.             /* place parameter block back into the "Available" queue */
  525.         Enqueue((QElemPtr)dspPBPtr,&gAvailQueue);
  526.     else    /* some kind of error was returned */
  527.             /* place parameter block back into the "Done" queue */
  528.         Enqueue((QElemPtr)dspPBPtr,&gDoneQueue);
  529. }
  530.  
  531. // *****************************************************************
  532. // *    sendAttnMsg
  533. // *
  534. // *    this is a generic attention message sending routine.  all 
  535. // *    attention messages are sent async using a shared buffer.   
  536. // *    the message code and the size of the message are passed to
  537. // *    this proc.
  538. // *****************************************************************
  539. void sendAttnMsg(DSPPBPtr dspPBPtr,
  540.                  short buffSize,
  541.                  Ptr attnData,
  542.                  short msg,
  543.                  short ccbRefNum)
  544. {
  545. TRattnParams *attnParmsPtr;
  546.  
  547. /* this is a generic attention message sending routine.  all attention messages are sent*/
  548. /* async using a shared buffer.  the message code and the size of the message are passed to */
  549. /* this proc.*/
  550.  
  551.     SetOurCompletionRoutine((ProcPtr)&sendAttnMsgCompRoutine,
  552.                             dspPBPtr);
  553.                             
  554.     dspPBPtr->ioCRefNum     = gADSPDrvrRefNum;
  555.     dspPBPtr->csCode         = dspAttention;
  556.     dspPBPtr->ccbRefNum     = ccbRefNum;
  557.     
  558.     attnParmsPtr = &dspPBPtr->u.attnParams;
  559.     attnParmsPtr->attnCode         = (unsigned short)msg;
  560.     attnParmsPtr->attnSize         = buffSize;
  561.     attnParmsPtr->attnData         = attnData;
  562.     attnParmsPtr->attnInterval     = 10;
  563.  
  564.     if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr)
  565.         Exit(DrvrErr);
  566. }
  567.  
  568.  
  569. // *****************************************************************
  570. // *    OpenPassiveCompletionRtn
  571. // *
  572. // *    when our passive open call completes this procedure
  573. // *    will get called.
  574. // *****************************************************************
  575. pascal void OpenPassiveCompletionRtn(DSPPBPtr dspPBPtr)
  576. {
  577.         
  578.     if (dspPBPtr->ioResult == noErr)
  579.     {
  580.         gJustConnected = true;
  581.             /* issue a read so we can catch
  582.                 any messages sent to us */
  583.         readIncoming(dspPBPtr,
  584.                     gCCBRefNum);    
  585.     }
  586.     else
  587.             /* place parameter block back into the "Done" queue */
  588.         Enqueue((QElemPtr)dspPBPtr,&gDoneQueue);
  589. }
  590.  
  591.  
  592. // *****************************************************************
  593. // *    DoPassiveOpen
  594. // *
  595. // *    issues an asynchronous passive open call. Any machine wishing
  596. // *    to connect to us must only send us an open request (dspOpen, 
  597. // *    ocRequest mode). Once we get a request, our completion routine
  598. // *    is called and the connection is established.
  599. // *****************************************************************
  600. void DoPassiveOpen(DSPPBPtr dspPBPtr,
  601.                     short ccbRefNum)
  602. {
  603.     AddrBlock filterAddress;
  604.     TRopenParams *openPBPtr;
  605.  
  606.  
  607.             /* send an open request */
  608.         SetOurCompletionRoutine((ProcPtr)&OpenPassiveCompletionRtn,
  609.                                 dspPBPtr);
  610.         dspPBPtr->ioCRefNum     = gADSPDrvrRefNum;
  611.         dspPBPtr->csCode         = dspOpen;
  612.         dspPBPtr->ccbRefNum     = ccbRefNum; /* refNum of connection end    */
  613.  
  614.             /* accept open requests from anyone */
  615.         filterAddress.aNet         = 0;
  616.         filterAddress.aNode     = 0;
  617.         filterAddress.aSocket     = 0;
  618.         
  619.         openPBPtr = &dspPBPtr->u.openParams;
  620.         openPBPtr->filterAddress     = filterAddress;
  621.         openPBPtr->ocMode             = ocPassive;
  622.         openPBPtr->ocInterval         = 0;    /* use default value of 6 (1 second) */
  623.         openPBPtr->ocMaximum         = 255;    /* retransmit indefinitely */
  624.  
  625.         if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr)
  626.             Exit(dspOpenErr);
  627.         
  628. }
  629.  
  630. // *****************************************************************
  631. // *    adspOpenRqstCompletionRtn
  632. // *
  633. // *    when our open request call completes this procedure
  634. // *    will get called. If we dont get back any errors then the
  635. // *    connection is established with the target.
  636. // *****************************************************************
  637. pascal void adspOpenRqstCompletionRtn(DSPPBPtr dspPBPtr)
  638. {
  639.     if (dspPBPtr->ioResult == noErr)
  640.     {
  641.         gJustConnected = true;
  642.             /* issue a read so we can catch
  643.                 any messages sent to us */
  644.         readIncoming(dspPBPtr,
  645.                     gCCBRefNum);    
  646.     }
  647.     else
  648.             /* place parameter block back into the "Done" queue */
  649.         Enqueue((QElemPtr)dspPBPtr,&gDoneQueue);    
  650. }
  651.  
  652. // *****************************************************************
  653. // *    sendAnOpenConnReq
  654. // *
  655. // *    issues an open request call to the target.
  656. // *****************************************************************
  657. void sendAnOpenConnReq (DSPPBPtr dspPBPtr,
  658.                         AddrBlock theirAddress,
  659.                         short ccbRefNum)
  660. {
  661.     AddrBlock filterAddress;
  662.     TRopenParams *openPBPtr;
  663.  
  664.             /* make a connection only with the selected target */
  665.         filterAddress = theirAddress;
  666.  
  667.             /* send an open request */
  668.         SetOurCompletionRoutine((ProcPtr)&adspOpenRqstCompletionRtn,
  669.                                 dspPBPtr);
  670.         dspPBPtr->ioCRefNum     = gADSPDrvrRefNum;
  671.         dspPBPtr->csCode         = dspOpen;
  672.         dspPBPtr->ccbRefNum     = ccbRefNum;
  673.         
  674.             /* refNum of connection end    */
  675.         openPBPtr = &dspPBPtr->u.openParams;
  676.         openPBPtr->remoteAddress     = theirAddress;
  677.         openPBPtr->filterAddress     = filterAddress;
  678.         openPBPtr->ocMode             = ocRequest;
  679.         openPBPtr->ocInterval         = 6;
  680.         openPBPtr->ocMaximum         = 5;
  681.  
  682.         if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr)
  683.             Exit(dspOpenErr);
  684.         
  685. }
  686.  
  687. // *****************************************************************
  688. // *    connectToPeer
  689. // *
  690. // *    first checks to see if the target is still there. Next, it
  691. // *    issues an open request to the target (but it first closes
  692. // *    the connection end which forces any prior passive open calls to
  693. // *    complete).
  694. // *****************************************************************
  695. void connectToPeer()
  696. {
  697.     NBPparms         *nbpParms;
  698.     MPPParamBlock     pbLKP;
  699.     char             returnBuffer[kLookupBufSize];
  700.     EntityName         abEntity;
  701.     AddrBlock         address;
  702.     NamesTableEntry namesTableEntry;
  703.     DSPPBPtr         dspPBPtr;
  704.     
  705.         if (gMyCCB.state == sClosed ||
  706.             gMyCCB.state == sPassive)
  707.         {
  708.             NBPSetEntity((Ptr)&namesTableEntry, gObjStr, gTypeStr, gZoneString);
  709.             
  710.             nbpParms = &pbLKP.NBP;
  711.             
  712.             nbpParms->interval                     = 3;
  713.             nbpParms->count                     = 3;
  714.             nbpParms->NBPPtrs.entityPtr         = (Ptr)&namesTableEntry;
  715.             nbpParms->parm.Lookup.retBuffSize     = kLookupBufSize;
  716.             nbpParms->parm.Lookup.retBuffPtr     = &returnBuffer;
  717.             nbpParms->parm.Lookup.maxToGet         = 1;
  718.  
  719.                 /* see if the target still exists */
  720.             if (PLookupName(&pbLKP, false) == noErr)
  721.             {
  722.                 if ( nbpParms->parm.Lookup.numGotten > 0)
  723.                 {
  724.                         /* look for the target in our return buffer */
  725.                     if (NBPExtract(returnBuffer, 
  726.                                     nbpParms->parm.Lookup.numGotten,
  727.                                     1,
  728.                                     &abEntity,
  729.                                     &address) == noErr)
  730.                     {
  731.                             /* if a passive open has been issued, we must first close the connection end (which
  732.                                 will cancel the open) before we can issue an open request to the target */
  733.                         if (gMyCCB.state == sPassive)
  734.                         {
  735.                             CloseTheConnection(gCCBRefNum);
  736.                         }
  737.                         
  738.                         dspPBPtr = GetQElement(&gAvailQueue);
  739.                         if (dspPBPtr != NULL)
  740.                         {
  741.                                 /*    issue an open request to the target */
  742.                             sendAnOpenConnReq(dspPBPtr,
  743.                                               address,
  744.                                               gCCBRefNum);
  745.                         }
  746.                     }
  747.                             
  748.                 }
  749.                 else    /* target not found */
  750.                     ShowError(noTargetErr);
  751.             }
  752.             
  753.         }
  754.         else        /* disconnect */
  755.         {
  756.             CloseConnection();
  757.         }
  758. }
  759.  
  760. // *****************************************************************
  761. // *    readIncomingComp
  762. // *
  763. // *    this routine is called when our asynchronous dspRead call
  764. // *    completes.
  765. // *****************************************************************
  766. pascal void readIncomingComp(DSPPBPtr dspPBPtr)
  767. {
  768.     if (dspPBPtr->ioResult == noErr)
  769.     {
  770.             /* place parameter block back into the "Read" queue */
  771.         Enqueue((QElemPtr)dspPBPtr,&gReadQueue);
  772.     }
  773.     else    /* error occurred */
  774.     {
  775.             /* place parameter block back into the "Done" queue */
  776.         Enqueue((QElemPtr)dspPBPtr,&gDoneQueue);
  777.     }
  778.     
  779. }
  780.  
  781. // *****************************************************************
  782. // *    readIncoming
  783. // *
  784. // *    issues an asynchronous dspRead to read any incoming messages
  785. // *****************************************************************
  786. void readIncoming(DSPPBPtr dspPBPtr,
  787.                     short ccbRefNum)
  788. {
  789. TRioParams *ioPBPtr;
  790.  
  791.     SetOurCompletionRoutine((ProcPtr)&readIncomingComp,
  792.                             dspPBPtr);
  793.     dspPBPtr->ioCRefNum     = gADSPDrvrRefNum;
  794.     dspPBPtr->csCode         = dspRead;
  795.     dspPBPtr->ccbRefNum     = ccbRefNum;
  796.     
  797.     ioPBPtr = &dspPBPtr->u.ioParams;
  798.     ioPBPtr->reqCount         = Qsize;
  799.     ioPBPtr->dataPtr         = receiveBuffer;
  800.  
  801.     if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr)
  802.         Exit(DrvrErr);
  803.         
  804. }
  805.  
  806. // *****************************************************************
  807. // *    writeComp
  808. // *
  809. // *    when our asynchronous dspWrite completes this routine will get
  810. // *    called.
  811. // *****************************************************************
  812. pascal void writeComp(DSPPBPtr dspPBPtr)
  813. {
  814.         /* place parameter block back into the "Done" queue */
  815.     Enqueue((QElemPtr)dspPBPtr,&gDoneQueue);    
  816. }
  817.  
  818. // *****************************************************************
  819. // *    writeOutgoing
  820. // *
  821. // *    issues an asynchronous dspWrite which sends any text that has
  822. // *    been entered to the target machine.
  823. // *****************************************************************
  824. void writeOutgoing(DSPPBPtr dspPBPtr,
  825.                     short ccbRefNum,
  826.                     Ptr dataPtr,
  827.                     short reqCount)
  828. {
  829.     TRioParams *ioPBPtr;
  830.  
  831.         SetOurCompletionRoutine((ProcPtr)&writeComp,
  832.                                 dspPBPtr);
  833.         dspPBPtr->ioCRefNum     = gADSPDrvrRefNum;
  834.         dspPBPtr->csCode         = dspWrite;
  835.         dspPBPtr->ccbRefNum     = ccbRefNum;
  836.         
  837.         ioPBPtr = &dspPBPtr->u.ioParams;
  838.         ioPBPtr->reqCount         = reqCount;
  839.         ioPBPtr->dataPtr         = dataPtr;
  840.         ioPBPtr->eom             = 1;
  841.         ioPBPtr->flush            = 1;
  842.  
  843.         if (PBControl((ParmBlkPtr)dspPBPtr, true) != noErr)
  844.             Exit(DrvrErr);
  845.  
  846. }
  847.  
  848. // *****************************************************************
  849. // *    sendTime
  850. // *
  851. // *    this procedure sends an attention message packet with our
  852. // *    time to the remote Mac.
  853. // *****************************************************************
  854. void sendTime()
  855. {
  856.     unsigned long secs;
  857.     DSPPBPtr dspPBPtr;
  858.  
  859.         GetDateTime(&secs);
  860.         BlockMove(&secs, outAttnBuff, 4);
  861.         dspPBPtr = GetQElement(&gAvailQueue);
  862.         if (dspPBPtr != NULL)
  863.         {
  864.             sendAttnMsg(dspPBPtr,
  865.                     4,
  866.                     outAttnBuff,
  867.                     kDisplayTime,
  868.                     gCCBRefNum);
  869.         }
  870. }
  871.  
  872. // *****************************************************************
  873. // *    sendMyName
  874. // *
  875. // *    this procedure sends an attention message packet with our 
  876. // *    Chooser name to the remote Mac.
  877. // *****************************************************************
  878. void sendMyName()
  879. {
  880.     DSPPBPtr dspPBPtr;
  881.     Str255 str;
  882.  
  883.         BlockMove(myName,str,myName[0]+1);
  884.         BlockMove(&str, outAttnBuff, 256);
  885.         
  886.         dspPBPtr = GetQElement(&gAvailQueue);
  887.         if (dspPBPtr != NULL)
  888.         {
  889.             sendAttnMsg(dspPBPtr,
  890.                         256,
  891.                         outAttnBuff,
  892.                         kDisplayTheirName,
  893.                         gCCBRefNum);
  894.         }
  895. }
  896.  
  897.  
  898. // *****************************************************************
  899. // *    signalConnect
  900. // *
  901. // *    after our passive open call has completed with an open request, 
  902. // *    or after an open request that we have issued to the target has
  903. // *    completed, we set a flag which causes this routine to get called.
  904. // *    This routine then sends the Chooser name of our machine to the
  905. // *    target.
  906. // *****************************************************************
  907. void signalConnect()
  908. {
  909.  
  910.     SysBeep(1);
  911.     changeConnectButtonState();
  912.     
  913.         /* send our machine's name to the other end */
  914.     sendMyName();
  915.  
  916.         /*Change selection to outgoing text TERecord */
  917.     SelIText(myDialog, kOutgoingTextID, 0, 32767);
  918. }
  919.  
  920. // *****************************************************************
  921. // *    checkAttnMsgs
  922. // *
  923. // *    If an attention message has been sent, we process it here.
  924. // *****************************************************************
  925. void checkAttnMsgs()
  926. {
  927.     switch(gMyCCB.attnCode)
  928.     {
  929.         case kDisplayTime:
  930.             DisplayTime();
  931.             break;
  932.         case kDisplayTheirName:
  933.             DisplayTheirName();
  934.             break;
  935.     }
  936. }
  937.  
  938. // *****************************************************************
  939. // *    DoConnectionEvents
  940. // *
  941. // *    This routine checks for unsolicited connection events and
  942. // *    processes them accordingly.
  943. // *****************************************************************
  944. void DoConnectionEvents()
  945. {
  946.     short state;
  947.     Byte flags;
  948.  
  949.         state = gMyCCB.state;
  950.         flags = gMyCCB.userFlags;
  951.  
  952.         if (state == sOpen)
  953.             DisplayCurrentStatus("\pConnection established.");
  954.         else if (state == sClosed)
  955.             DisplayCurrentStatus("\pNot currently connected.");
  956.         else if (state == sPassive)
  957.             DisplayCurrentStatus("\pWaiting to accept connection.");
  958.         
  959.         if (flags & eAttention)
  960.         {
  961.             checkAttnMsgs();
  962.                 /* we must clear the bit after we have used it or we wont
  963.                     get any more messages */
  964.             BitClr(&gMyCCB.userFlags,2);
  965.         }
  966.         else if (flags & eClosed)
  967.         {
  968.             DisplayCurrentStatus("\pConnection was closed.");
  969.                 /* we must clear the bit after we have used it or we wont
  970.                     get any more messages */
  971.             BitClr(&gMyCCB.userFlags,0);
  972.             CloseConnection();
  973.         }
  974.                 /* after two minutes or so if the connection has broken we'll be notified by */
  975.                 /* the .DSP driver with an eTearDown message */
  976.         else if (flags & eTearDown)
  977.         {
  978.             SysBeep(2);
  979.             SysBeep(2);
  980.             DisplayCurrentStatus("\pConnection torn down.");
  981.                 /* we must clear the bit after we have used it or we wont
  982.                     get any more messages */
  983.             BitClr(&gMyCCB.userFlags,1);
  984.             CloseConnection();
  985.         }
  986.  
  987. }
  988.  
  989. // *****************************************************************
  990. // *    CheckDoneQueue
  991. // *
  992. // *    This routine looks through the "Done" queue for calls that
  993. // *    have completed and reports any errors.
  994. // *****************************************************************
  995. void CheckDoneQueue()
  996. {
  997. QElemPtr qElemPtr;
  998. DSPPBPtr dspPBPtr;
  999. OSErr err;
  1000.  
  1001.         /* have any Writes completed? */
  1002.     if (gDoneQueue.qHead != nil)
  1003.     {
  1004.         qElemPtr = gDoneQueue.qHead;
  1005.         err = Dequeue((QElemPtr)qElemPtr,&gDoneQueue);
  1006.         if (err == noErr)
  1007.         {
  1008.             dspPBPtr = (DSPPBPtr)qElemPtr;
  1009.                 /* were there any errors on this particular call? */
  1010.             if (dspPBPtr->ioResult != noErr)
  1011.             {
  1012.                 ShowADSPError(dspPBPtr);
  1013.             }
  1014.  
  1015.                 /* place queue element back into the "available" queue */
  1016.             Enqueue((QElemPtr)qElemPtr,&gAvailQueue);
  1017.         }
  1018.     }
  1019.  
  1020. }
  1021.  
  1022. // *****************************************************************
  1023. // *    CheckCompletedReads
  1024. // *
  1025. // *    This routine looks through the "Read" queue for calls that
  1026. // *    have completed, displays the text that was read and re-issues
  1027. // *    another asynchronous read call.
  1028. // *****************************************************************
  1029. void CheckCompletedReads()
  1030. {
  1031. QElemPtr qElemPtr;
  1032. DSPPBPtr dspPBPtr;
  1033. OSErr err;
  1034.  
  1035.         /* have any reads completed? */
  1036.     if (gReadQueue.qHead != nil)
  1037.     {
  1038.         qElemPtr = gReadQueue.qHead;
  1039.         err = Dequeue((QElemPtr)qElemPtr,&gReadQueue);
  1040.         if (err == noErr)
  1041.         {
  1042.             dspPBPtr = (DSPPBPtr)qElemPtr;
  1043.                 /* were there any errors on this particular read call? */
  1044.             if (dspPBPtr->ioResult == noErr)
  1045.             {
  1046.                     /* show the text */
  1047.                 DisplayIncomingText(dspPBPtr);
  1048.             }
  1049.             else
  1050.             {
  1051.                 ShowADSPError(dspPBPtr);
  1052.             }
  1053.  
  1054.                 /* go ahead and issue another asynchronous read */
  1055.             readIncoming(dspPBPtr,
  1056.                         gCCBRefNum);
  1057.         }
  1058.     }
  1059.  
  1060. }
  1061.  
  1062. // *****************************************************************
  1063. // *    ADSPLoop
  1064. // *
  1065. // *    This is called from our idle procedure in our main event
  1066. // *    loop. If a connection is made, we learn about it here. If we
  1067. // *    do detect that a connection has been made, we check for
  1068. // *    connection events and issue read and write calls here.
  1069. // *****************************************************************
  1070. void ADSPLoop()
  1071. {
  1072.  
  1073.         /* check to see if our passive open completed with an open
  1074.             request from another machine OR if an open request that
  1075.             we issued to the target has completed */
  1076.     if (gJustConnected == true)
  1077.     {
  1078.             /* reset our flag */
  1079.         gJustConnected = false;
  1080.  
  1081.             /* set status message to indicate we have a connection */
  1082.         signalConnect();
  1083.     }
  1084.  
  1085.         /* check for connection events */
  1086.     DoConnectionEvents();
  1087.  
  1088.     if (gMyCCB.state != sClosed)
  1089.     {
  1090.             /* have any read calls completed? */
  1091.         CheckCompletedReads();
  1092.     
  1093.             /* check for all other calls that have completed */
  1094.         CheckDoneQueue();
  1095.     }
  1096.  
  1097.         /* do we currently have a connection? */
  1098.     if (gMyCCB.state == sOpen)
  1099.     {
  1100.             /* we have a connection so send our clock time
  1101.                 to the other machine */
  1102.         sendTime();
  1103.  
  1104.     }
  1105.  
  1106.  
  1107. }
  1108.  
  1109.  
  1110. // *****************************************************************
  1111. // *    SetUpADSPError
  1112. // *
  1113. // *    sets our error string for the desired error code
  1114. // *****************************************************************
  1115. void SetUpADSPError(OSErr err, StringPtr displayStr)
  1116. {
  1117.     switch (err)
  1118.     {
  1119.         case errAborted:
  1120.             PStrCat("\pControl call was aborted.",(Ptr)displayStr);
  1121.           break;
  1122.           
  1123.         case errState:
  1124.             PStrCat("\pBad connection state for this operation.",(Ptr)displayStr);
  1125.           break;
  1126.  
  1127.         case errOpening:
  1128.             PStrCat("\pOpen connection request failed.",(Ptr)displayStr);
  1129.           break;
  1130.           
  1131.         case errOpenDenied:
  1132.             PStrCat("\pOpen connection request was denied.",(Ptr)displayStr);
  1133.           break;
  1134.           
  1135.         default:
  1136.             NumToString(err,(Ptr)displayStr);
  1137.         
  1138.     }
  1139.  
  1140. }
  1141.  
  1142. // *****************************************************************
  1143. // *    ShowADSPError
  1144. // *
  1145. // *    If one of our asynchronous adsp calls returned an error, the
  1146. // *    parameter block gets stuffed into an error OSQueue by the completion
  1147. // *    routine. This error queue is checked periodically by this routine.
  1148. // *    If the queue is not empty, then we got an error so we display it here
  1149. // *    and do any processing of the error that we want.
  1150. // *****************************************************************
  1151. void ShowADSPError(DSPPBPtr dspPBPtr)
  1152. {
  1153.     short itemHit;
  1154.     Str255 displayStr,theError;
  1155.     
  1156.  
  1157.             displayStr[0] = 0;
  1158.             
  1159.                 /*  Use cscode field of the parameter block
  1160.                    to see which call this error is for*/
  1161.             
  1162.             switch (dspPBPtr->csCode)
  1163.             {
  1164.                 case dspRead:
  1165.                         /* We'll ignore the "errState" error for now,
  1166.                             since you'll get this when you close a 
  1167.                             connection (and we don't really need to
  1168.                             report it in that case) */
  1169.                     if (dspPBPtr->ioResult != errState)
  1170.                     {
  1171.                         CopyPstr("\pdspRead error. ",&displayStr);
  1172.                         SetUpADSPError(dspPBPtr->ioResult, &displayStr);
  1173.                     }
  1174.                  break;
  1175.     
  1176.                 case dspWrite:
  1177.                     CopyPstr("\pdspWrite error. ",&displayStr);
  1178.                     SetUpADSPError(dspPBPtr->ioResult, &displayStr);
  1179.                  break;
  1180.             
  1181.                 case dspAttention:
  1182.                         /* ignore aborts that were caused by dspRemove or dspClose */
  1183.                     if ((dspPBPtr->ioResult != errAborted) 
  1184.                         && (dspPBPtr->ioResult != errState))
  1185.                     {
  1186.                         CopyPstr("\pdspAttention error. ",&displayStr);
  1187.                         SetUpADSPError(dspPBPtr->ioResult, &displayStr);
  1188.                     }
  1189.                  break;
  1190.  
  1191.                 case dspOpen:
  1192.                         /* ignore errAborted (-1279), request aborted by dspRemove or
  1193.                             dspClose - the reason being that if we have a dspOpen (ocPassive
  1194.                             mode) issued and then we want to connect to another machine, we
  1195.                             must first close the connection end (cancelling the passive open)
  1196.                             which would result in this error */
  1197.                     if (dspPBPtr->ioResult != errAborted)
  1198.                     {
  1199.                         CopyPstr("\pdspOpen error. ",&displayStr);
  1200.                         SetUpADSPError(dspPBPtr->ioResult, &displayStr);
  1201.                     }
  1202.                  break;
  1203.  
  1204.                 case dspCLListen:
  1205.                     CopyPstr("\pdspCLListen error. ",&displayStr);
  1206.                     SetUpADSPError(dspPBPtr->ioResult, &displayStr);
  1207.                  break;
  1208.     
  1209.                 default:
  1210.                     CopyPstr("\pError: ",&displayStr);
  1211.                     NumToString(dspPBPtr->ioResult,theError);
  1212.                     PStrCat(theError,(Ptr)displayStr);
  1213.             }
  1214.  
  1215.                 /* if we have a message we want to show, put up a dialog
  1216.                     for the user */
  1217.             if (displayStr[0] != 0)
  1218.             {
  1219.                 ParamText(displayStr,"\p","\p","\p");
  1220.                 itemHit = Alert(rErrorDialog, nil);
  1221.             }        
  1222. }